package vis.core.common.security;


import com.alibaba.fastjson2.JSONArray;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import vis.core.common.properties.VisProSecurity;
import vis.core.common.util.StringKit;
import vis.core.domain.sys.MSG;
import vis.core.domain.sys.ServiceException;
import vis.core.domain.sys.config.SysConfig;
import vis.core.service.sys.SysResService;

import java.util.ArrayList;
import java.util.List;

/**
 * 非注解开发时的，细粒度权限拦截
 *
 * @author 王永吉
 */
@Slf4j
@Component
public class AuthVisInterceptor implements HandlerInterceptor {

    @Resource
    private VisProSecurity visProSecurity;
    @Resource
    private SysConfig sysConfig;
    @Resource
    private SysResService sysResService;

    //资源匹配对象
    public static final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        response.setHeader("Access-Control-Allow-Origin", "*");
//        response.setHeader("Access-Control-Allow-Headers", "authorization,Authorization,Token,Auth,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type");
//
//        //放行OPTIONS
//        String requestMethod = request.getMethod();
//        if (requestMethod.equals("OPTIONS")) return true;

        //开放访问接口，无需权限校验
        AuthPublic classAuthPublic = ((HandlerMethod) handler).getBeanType().getAnnotation(AuthPublic.class);
        AuthPublic methodAuthPublic = ((HandlerMethod) handler).getMethod().getAnnotation(AuthPublic.class);
        if (classAuthPublic != null || methodAuthPublic != null) return true;

        //不需要身份验证，仅需要登录验证
        AuthOnlyLogin classAuth = ((HandlerMethod) handler).getBeanType().getAnnotation(AuthOnlyLogin.class);
        AuthOnlyLogin methodAuth = ((HandlerMethod) handler).getMethod().getAnnotation(AuthOnlyLogin.class);
        if (classAuth != null || methodAuth != null) return true;

        //检查是否具备访问权限
        return checkHasRes(request);
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) {
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView) {
    }


    private boolean checkHasRes(HttpServletRequest request) {
        //判断：公开资源，不需要登录
        String requestURI = request.getRequestURI();
        if (isIgnore(requestURI)) return true;

        //检查Token
        AuthUser currentUser = AuthKit.getCurrentUser();

        //超级用户放行
        if (currentUser.getIsRoot()) return true;

        //
        //检查角色和部门 是否具备资源的访问权限
        boolean hasRes = sysResService.checkHasRes(requestURI, currentUser.getRoleIds(), currentUser.getOrgIds());
        if (hasRes) return true;

        //
        //权限不足
        log.error("权限不足 requestURI:{} ；userAccount:{}", requestURI, currentUser.getAccount());

        throw new ServiceException(MSG.ER_403);
    }

    /**
     * 匹配放行URI
     */
    private boolean isIgnore(String requestURI) {
        List<String> uriList = new ArrayList<>();

        //先走数据库
        String s = sysConfig.resIgnore();
        if (StringKit.isBlank(s)) uriList = visProSecurity.getResIgnore();

        //数据库没有的话，走本地配置文件
        if (StringKit.isNotBlank(s)) uriList = JSONArray.parseArray(s, String.class);

        for (String ignoreUrl : uriList) {
            boolean match = pathMatcher.match(ignoreUrl, requestURI);
            if (match) return true;
        }
        return false;
    }

//    public void mastHasRole(String requestURI, AuthUser currentUser) {
//        List<String> userRoleIds = currentUser.getRoleIds();
//
//        HashMap<String, String> resMastRole = ablSecurityProperties.getResMastRole();
//
//        Set<String> allRes = resMastRole.keySet();
//
//        //遍历所有能匹配上的资源
//        for (String resPath : allRes) {
//            boolean match = pathMatcher.match(resPath, requestURI);
//            if (match) {
//                //检查该资源所需的全部角色
//                ArrayList<String> mastHasRoleIds = StringKit.split(resMastRole.get(resPath));
//                //对应该资源，如果用户不具备所有角色，则抛出异常
//                for (String mastHasRoleId : mastHasRoleIds) {
//                    if (!userRoleIds.contains(mastHasRoleId)) {
//                        log.error("权限不足  必须具备角色：{}  requestURI:{}  userAccount:{}  userRoleIds:{}", mastHasRoleId, requestURI, currentUser.getAccount(), userRoleIds);
//                        throw new SrsException(MSG.ER_403);
//                    }
//                }
//            }
//        }
//    }
}
